package edu.spangler.dang.FriendTracker.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

/**
 * The content provider for storing friends' locations.
 * @author Paul Spangler
 */

public class FriendsProvider extends ContentProvider
{
    /**
     * The name of the Friends content provider.
     */
    
    public static final String Authority = "edu.spangler.dang.FriendTracker.provider.Friends";
      
    private static final int FriendsUri = 1;
    private static final int FriendsIDUri = 2;
    private static final UriMatcher _uriMatcher;
    
    private SQLiteDatabase _database;
    private FriendsDatabase _databaseHelper;
    
    static
    {
        _uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        _uriMatcher.addURI(Authority, "friends", FriendsUri);
        _uriMatcher.addURI(Authority, "friends/#", FriendsIDUri);      
    }

    /**
     * Implement this to initialize your content provider on startup.
     * @return True if the provider was successfully loaded, false otherwise.
     */
    
    @Override
    public boolean onCreate()
    {
        _databaseHelper = new FriendsDatabase(getContext());
        return true;
    }

    /**
     * Implement this to handle query requests from clients.
     * @param uri The URI to query.
     * @param projection The list of columns to put into the cursor. If null all columns are included.
     * @param selection A selection criteria to apply when filtering rows. If null then all rows are included.
     * @param selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
     * @param sortOrder How the rows in the cursor should be sorted. If null then the provider is free to define the sort order.
     * @return A Cursor or null.
     */

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        
        switch (_uriMatcher.match(uri))
        {
            case FriendsUri:
                builder.setTables(FriendsDatabase.FriendsTable);
                break;
            
            case FriendsIDUri:
                builder.setTables(FriendsDatabase.FriendsTable);
                builder.appendWhere(Friends._ID + " = " + uri.getPathSegments().get(1));
                break;
            
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        if (_database == null)
        {
            _database = _databaseHelper.getWritableDatabase();
        }
        
        Cursor cursor = builder.query(_database, projection, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        
        return cursor;
    }

    /**
     * Implement this to handle requests for the MIME type of the data at the given URI.
     * @param uri The URI to query.
     * @return A MIME type string, or null if there is no type.
     */

    @Override
    public String getType(Uri uri)
    {
        switch (_uriMatcher.match(uri))
        {
            case FriendsUri:
                return Friends.ContentType;
            
            case FriendsIDUri:
                return Friends.ContentTypeID;
            
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    /**
     * Implement this to handle requests to insert a new row.
     * @param uri The content:// URI of the insertion request.
     * @param values A set of column_name/value pairs to add to the database.
     * @return The URI for the newly inserted item.
     */

    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        if (_uriMatcher.match(uri) != FriendsUri)
        {
            throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        
        if (values == null)
        {
            //noinspection AssignmentToMethodParameter
            values = new ContentValues();
        }
        
        if (_database == null)
        {
            _database = _databaseHelper.getWritableDatabase();
        }
        
        long rowId = _database.insert(FriendsDatabase.FriendsTable, Friends.Name, values);
        
        if (rowId <= 0)
        {
            throw new SQLException("Failed to insert into the database.");
        }
        
        Uri rowUri = ContentUris.withAppendedId(uri, rowId);
        getContext().getContentResolver().notifyChange(rowUri, null);
        
        return rowUri;
    }

    /**
     * Implement this to handle requests to delete one or more rows.
     * @param uri The full URI to query, including a row ID (if a specific record is requested).
     * @param selection An optional restriction to apply to rows when deleting.
     * @param selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
     * @return The number of rows affected.
     */

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {
        int count;
        
        if (_database == null)
        {
            _database = _databaseHelper.getWritableDatabase();
        }
        
        switch (_uriMatcher.match(uri))
        {
            case FriendsUri:
                count = _database.delete(FriendsDatabase.FriendsTable, selection, selectionArgs);
                break;
            
            case FriendsIDUri:
                String id = uri.getPathSegments().get(1);
                String idSelection = Friends._ID + " = " + id;
                
                if (selection != null && !selection.isEmpty())
                {
                    idSelection += " AND (" + selection + ")";
                }
                
                count = _database.delete(FriendsDatabase.FriendsTable, idSelection, selectionArgs);
                break;
                
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);    
        }
        
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    /**
     * Implement this to handle requests to update one or more rows.
     * @param uri The URI to query. This can potentially have a record ID if this is an update request for a specific record.
     * @param values A Bundle mapping from column names to new column values (NULL is a valid value).
     * @param selection An optional filter to match rows to update.
     * @param selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
     * @return The number of rows affected.
     */

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    {
        int count;
        
        if (_database == null)
        {
            _database = _databaseHelper.getWritableDatabase();
        }
        
        switch (_uriMatcher.match(uri))
        {
            case FriendsUri:
                count = _database.update(FriendsDatabase.FriendsTable, values, selection, selectionArgs);
                break;
            
            case FriendsIDUri:
                String id = uri.getPathSegments().get(1);
                String idSelection = Friends._ID + " = " + id;
                
                if (selection != null && !selection.isEmpty())
                {
                    idSelection += " AND (" + selection + ")";
                }
                
                count = _database.update(FriendsDatabase.FriendsTable, values, idSelection, selectionArgs);
                break;
                
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);    
        }
        
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}
